﻿using System;
using System.Collections.Generic;
using System.Text;
using RedCorona.Net;
using System.Diagnostics;

namespace HovisPresent.Net
{
	public delegate void ServerClientClosed(ServerConnection server);
	public delegate void ServerClientMessageRecieved( ServerConnection server, MasterMessage message, string[] parameters);
	public delegate void ServerConnected(ServerConnection server);

	public class ServerConnection : Connection
	{
		protected Server server;
		protected ClientInfo client;

		/// <summary>
		/// Occurs when server client message recieved. Note that the paramters includes the 
		/// command text at position [0]
		/// </summary>
		public event ServerClientMessageRecieved OnServerClientMessageRecieved;
		public event ServerClientClosed OnServerClientClosed;
		public event ServerConnected OnServerConnected;

		/// <summary>
		/// Listens the specified port.
		/// </summary>
		/// <param name="port">The port.</param>
		public void Listen(int port) {
			server = new Server(port, new ClientEvent(OnClientConnect));
		}

		/// <summary>
		/// Called when [client connect].
		/// </summary>
		/// <param name="serv">The serv.</param>
		/// <param name="new_client">The new_client.</param>
		/// <returns></returns>
		private bool OnClientConnect(Server serv, ClientInfo new_client) {
			if (client != null)
				return false;
			client = new_client;
			client.OnRead += new ConnectionRead(OnMessageRecieved);
			client.OnClose +=new ConnectionClosed(OnClientClosed);
			client.Delimiter = "\r\n";

			if (OnServerConnected!=null)
				OnServerConnected(this);

			return true; // allow this connection
		}

		/// <summary>
		/// Closes this instance.
		/// </summary>
		public void Close() {
			try {
				if (server != null)
					server.Close();
			} catch (Exception e) {
				Debug.WriteLine(e.ToString());
			}

			try {
				if (client != null) {
					client.Close();
				}
			} catch (Exception e) {
				Debug.WriteLine(e.ToString());
			}
			
			OnServerClientClosed = null;
			OnServerClientMessageRecieved = null;
			OnServerConnected = null;
		}

		/// <summary>
		/// Called when client [message recieved].
		/// </summary>
		/// <param name="ci">The ci.</param>
		/// <param name="text">The text.</param>
		private void OnMessageRecieved(ClientInfo ci, String text) {
			Debug.WriteLine("Server client Received text message: " + text);
			
			string[] parameters = SplitMessage(text);
			if (parameters == null) {
				Debug.WriteLine("Invalid master message format");
				SendInvalidCommand();
				return;
			}

			if ( !Enum.IsDefined( typeof(MasterMessage), parameters[0]) ) {
				Debug.WriteLine("Invalid master message command");
				SendInvalidCommand();
				return;
			}

			MasterMessage message = (MasterMessage) Enum.Parse(typeof(MasterMessage),parameters[0]);

			if (OnServerClientMessageRecieved!=null)
				OnServerClientMessageRecieved(this, message, parameters);
		}

		/// <summary>
		/// Called when client [closed].
		/// </summary>
		/// <param name="ci">The ci.</param>
		private void OnClientClosed(ClientInfo ci) {
			Debug.WriteLine("Server Client closed");
			
			if (OnServerClientClosed != null)
				OnServerClientClosed(this);
			
			client = null;
		}

		/// <summary>
		/// Creates the message.
		/// </summary>
		/// <param name="m">The m.</param>
		/// <param name="p">The p.</param>
		public void SendMessage(SlaveMessage m, params string[] p) {
			SendMessage( CreateMessage(m.ToString(), p) );
		}

		/// <summary>
		/// Sends the message, adding line delimited character
		/// </summary>
		/// <param name="message">The message.</param>
		private void SendMessage(string message) {
			if (client == null || client.Closed)
				return;
			message += client.Delimiter;
			client.Send(message);
		}

		#region Slave to Master messages

		/// <summary>
		/// Sends the yes alive message
		/// </summary>
		public void SendYesAlive() {
			SendMessage(SlaveMessage.YesAlive);
		}

		/// <summary>
		/// Sends the error.
		/// </summary>
		public void SendError(string error) {
			SendMessage(SlaveMessage.Error, error);
		}

		/// <summary>
		/// Sends the invalid parameter error.
		/// </summary>
		public void SendInvalidParameterError() {
			SendError("Invalid Parameter/s");
		}

		/// <summary>
		/// Sends the invalid command.
		/// </summary>
		public void SendInvalidCommand() {
			SendError("Invalid Command");
		}
		#endregion
	}
}
